#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>

#include <asm/io.h>
#include <asm/uaccess.h>

struct led_dev{
	int dev_major;
	struct class *cls;
	struct device *dev;
	struct resource *res;
	void *reg_base;
};

struct led_dev *samsung_led;

ssize_t write_led_dev(struct file *filp,const char __user *buf,size_t count,loff_t *fops)
{
	int value;
	int ret;
	ret=raw_copy_from_user(&value,buf,count);
	if(ret>0)
	{
		printk("raw_copy_from_user failed\n");
		return -EFAULT;
	}
	if(value)
	{
		writel(readl(samsung_led->reg_base+4) | (0x1<<0),samsung_led->reg_base+4);
	}
	else
	{
		writel(readl(samsung_led->reg_base+4) & ~(0x1<<0),samsung_led->reg_base+4);
	}
	return count;
}
int open_led_dev(struct inode *inode,struct file *filp)
{
	//printk("-----open-------\n");
	return 0;
}
int close_led_dev(struct inode *inode,struct file *filp)
{
//	printk("--------cloe------\n");
	return 0;
}
const struct file_operations led_fops={
	.open=open_led_dev,
	.write=write_led_dev,
	.release=close_led_dev,
};

int led_pdrv_probe(struct platform_device *pdev)
{
	int irqno;
//	printk("-----probe-------\n");
	samsung_led=kzalloc(sizeof(struct led_dev),GFP_KERNEL);
	if(samsung_led==NULL)
	{
		printk("kzalloc failed\n");
		return -ENOMEM;
	}

	samsung_led->dev_major = register_chrdev(0,"led_drv",&led_fops);
	samsung_led->cls=class_create(THIS_MODULE,"led_class");
	samsung_led->dev=device_create(samsung_led->cls,NULL,MKDEV(samsung_led->dev_major,0),NULL,"led0");
	samsung_led->res=platform_get_resource(pdev,IORESOURCE_MEM,1);
	irqno = platform_get_irq(pdev,1);
//	printk("irqno=%d\n",irqno);
	
	samsung_led->reg_base=ioremap(samsung_led->res->start,resource_size(samsung_led->res));

	writel(readl(samsung_led->reg_base)&~(0xf<<0)|(0x1<<0),samsung_led->reg_base);

	return 0;
}

int led_pdrv_remove(struct platform_device *pdev)
{
	printk("-----remove-------\n");
	iounmap(samsung_led->reg_base);
	device_destroy(samsung_led->cls,MKDEV(samsung_led->dev_major,0));
	class_destroy(samsung_led->cls);
	unregister_chrdev(samsung_led->dev_major,"led_drv");
	kfree(samsung_led);
	return 0;
}


const struct platform_device_id led_id_table[]={
	{"exynos4412_led",0x4444},
	{"exynos6818_led",0x4444},
};

struct platform_driver led_pdrv={
	.probe=led_pdrv_probe,
	.remove=led_pdrv_remove,
	.driver={
		.name = "samsung_led_drv",
	},
	.id_table=led_id_table,
};




static int __init drv_led_init(void)
{
	printk("-------init---------\n");
	return platform_driver_register(&led_pdrv);
}

static void __exit drv_led_exit(void)
{
	printk("-----------exit--------\n");
	platform_driver_unregister(&led_pdrv);
}

module_init(drv_led_init);
module_exit(drv_led_exit);
MODULE_LICENSE("GPL");
